package processor.hashmap;

import error.ClassError;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import processor.ProcessorSuperClass;

import tuples.StringListPair;
import tuples.StringPair;

/**
 * Contains several methods for working with HashMaps.
 * 
 * @author Shimu
 * 
 */
public class HashmapProcessor extends ProcessorSuperClass {

    private final static ClassError logger
            = new ClassError(HashmapProcessor.class.getName());

    public HashmapProcessor() {
    }

    public HashMap<String, String> toHashMap(ArrayList<String> strList) {
        HashMap<String, String> map = new HashMap<String, String>();
        int colon_index;
        String key, value;

        for (String str : strList) {
            colon_index = str.indexOf(":");
            if ((colon_index == -1) || (colon_index == str.length() - 1)) {
                continue;
            } else {
                key = str.substring(0, colon_index).trim();
                value = str.substring(colon_index + 1).trim();
                if (!key.isEmpty() && !value.isEmpty()) {
                    map.put(key, value);
                }
            }
        }

        return map;
    }

    /** Removes any white space from all the Strings in the given
    String array. */
    private String[] trimAll(String[] strList) {
        for (int i = 0; i < strList.length; i++) {
            strList[i] = strList[i].trim();
        }

        return strList;
    }

    public HashMap<String, String[]> 
            toHashMapStrArray(ArrayList<String> strList) {
        HashMap<String, String[]> map = new HashMap<String, String[]>();
        int colon_index;
        String key;
        String[] values;

        for (String str : strList) {
            colon_index = str.indexOf(":");
            if ((colon_index == -1) || (colon_index == str.length() - 1)) {
                continue;
            } else {
                key = str.substring(0, colon_index).trim();
                values = trimAll(str.substring(colon_index + 1).split(","));
                if (!key.isEmpty() && (values.length != 0)) {
                    map.put(key, values);
                }
            }
        }

        return map;
    }

    public HashMap<String, String> 
            toHashMap(String[] keys, String[] values) {
        HashMap<String, String> table = new HashMap<String, String>();

        if (keys.length != values.length) {
            logger.severe("Different number of keys and values!");
            return table;

        } else {
            for (int i = 0; i < keys.length; i++) {
                table.put(keys[i], values[i]);
            }
            return table;
        }
    }

    /**
     * Given a HashMap<String, String> returns a String[][] containing
     * the keys of the HashMap at String[i][0] and the values of the
     * HashMap at String[i][1].
     *
     * @param table
     * @return
     */
    public String[][] toDoubleArray(HashMap<String, String> table) {
        String[][] array = new String[table.size()][2];

        Set<String> keys = table.keySet();
        int index = 0;

        for (String k : keys) {
            array[index][0] = k;
            array[index][1] = table.get(k);
            index++;
        }

        return array;
    }

    /**
     * Given a HashMap<String, String> returns a List<StringPair> where each
     * StringPair stores one element from the HashMap.
     *
     * @see StringPair
     * @param table
     * @return
     */
    public List<StringPair> toStringPairArray(HashMap<String, String> table) {
        List<StringPair> array = new ArrayList<StringPair>();

        Set<String> keys = table.keySet();
        int index = 0;

        for (String k : keys) {
            array.add(new StringPair(k, table.get(k)));
            index++;
        }

        return array;
    }

    /**
     * Given a HashMap<String, ArrayList<String>> returns a
     * List<StringListPair> where
     * each StringListPair stores one element from the HashMap.
     *
     * @see StringListPair
     * @param table
     * @return
     */
    public List<StringListPair> toStringListPairArray(
            HashMap<String, ArrayList<String>> table) {
        List<StringListPair> array = new ArrayList<StringListPair>();

        Set<String> keys = table.keySet();
        int index = 0;

        for (String k : keys) {
            array.add(new StringListPair(k, table.get(k)));
            index++;
        }

        return array;
    }

    /**
     * Add the given key and value to the given table. If the given key already
     * exists,
     * then the given value will be add to the end of the existing entry's
     * value.
     *
     * @param table
     *            a HashMap<String, ArrayList<String>>
     * @param key
     *            a String
     * @param value
     *            a String
     */
    public void put(HashMap<String, ArrayList<String>> table, String key,
            String value) {

        if (table.containsKey(key)) {
            table.get(key).add(value);
        } else {
            ArrayList<String> array = new ArrayList<String>();
            array.add(value);
            table.put(key, new ArrayList<String>(array));
        }
    }

    /**
     * Add the given key and value to the given table. If the given key already
     * exists,
     * then the given value will be extended to the end of the existing entry's
     * value.
     *
     * @param table
     *            a HashMap<String, ArrayList<String>>
     * @param key
     *            a String
     * @param value
     *            a String
     */
    public void put(HashMap<String, ArrayList<String>> table, String key,
            ArrayList<String> value) {

        if (table.containsKey(key)) {
            table.get(key).addAll(value);
        } else {
            table.put(key, value);
        }
    }

    /**
     * Given a HashMap<String, String> returns a List<StringPair> containing
     * the elements from the HashMap sorted alphabetically by keys.
     *
     * @see StringPair
     * @param table
     * @return
     */
    public List<StringPair> sortByKey(HashMap<String, String> table) {
        List<StringPair> array = toStringPairArray(table);
        StringPair.sortByKey(array);
        return array;
    }

    /**
     * Given a HashMap<String, String> returns a List<StringPair> containing
     * the elements from the HashMap sorted alphabetically by value.
     *
     * @param table
     * @return
     */
    public List<StringPair> sortByValue(HashMap<String, String> table) {
        List<StringPair> array = toStringPairArray(table);
        StringPair.sortByValue(array);
        return array;
    }

    /**
     * Given a HashMap<String, ArrayList<String>> returns a
     * List<StringListPair>
     * containing the elements of the HashMap, sorted alphabetically by keys.
     * The ArrayList<String> of each element in the HashMap is also sorted.
     *
     * @see toStringListPairArray
     * @param table
     * @return
     */
    public List<StringListPair> sort(HashMap<String, ArrayList<String>> table) {
        List<StringListPair> array = toStringListPairArray(table);
        StringListPair.sortAll(array);
        return array;
    }
}
